﻿#pragma once
#pragma execution_character_set("utf-8")
// 本文件为utf-8 编码格式

/*
  图片滤镜处理工具类
  craete by geelou@qq.com
*/

#ifndef __GD__GDImageFilterUtil__
#define __GD__GDImageFilterUtil__

#include "CrossApp.h"

#define SAFECOLOR(color) color<0?0:(color>255?255:color)

class Color{
public:
	int R;
	int G;
	int B;
	Color(){}

	Color(int r, int g, int b) : R(r), G(g), B(b){}

	Color(int rgb){
		R = ((rgb & 0x00FF0000) >> 16);
		G = ((rgb & 0x0000FF00) >> 8);
		B = (rgb & 0x000000FF);
	}

	static int rgb(int r, int g, int b){
		return (255 << 24) + (r << 16) + (g << 8) + b;
	}
};

class HslColor
{

public:
	float h;
	float l;
	float s;

	HslColor(float _h, float _s, float _l)
	{
		h = _h;
		s = _s;
		l = _l;
	}


private:
	// HSL to RGB helper routine
	static double Hue_2_RGB(double v1, double v2, double vH)
	{
		if (vH < 0)
			vH += 1;
		if (vH > 1)
			vH -= 1;
		if ((6 * vH) < 1)
			return (v1 + (v2 - v1) * 6 * vH);
		if ((2 * vH) < 1)
			return v2;
		if ((3 * vH) < 2)
			return (v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6);
		return v1;
	}

	static float HueToRgb(float t1, float t2, float h)
	{
		if (h < 0)
		{
			h++;
		}
		if (h > 1)
		{
			h--;
		}
		if ((6 * h) < 1)
		{
			return (t1 + (((t2 - t1) * 6) * h));
		}
		if ((2 * h) < 1)
		{
			return t2;
		}
		if ((3 * h) < 2)
		{
			return (t1 + (((t2 - t1) * (0.6666667f - h)) * 6));
		}
		return t1;
	}

public:
	static int HslToRgb(HslColor hsl)
	{
		int r, g, b;
		if (hsl.h == 0)
		{
			// gray values
			r = g = b = (unsigned char)(hsl.l * 255);
		}
		else
		{
			double v1, v2;
			double hue = (double)hsl.h / 360;

			v2 = (hsl.l < 0.5) ?
				(hsl.l * (1 + hsl.s)) :
				((hsl.l + hsl.s) - (hsl.l * hsl.s));
			v1 = 2 * hsl.l - v2;

			r = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue + (1.0 / 3)));
			g = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue));
			b = (unsigned char)(255 * Hue_2_RGB(v1, v2, hue - (1.0 / 3)));
		}
		return (255 << 24) + (r << 16) + (g << 8) + b;
	}



	HslColor Interpolate(HslColor c2, float amount)
	{
		return HslColor(h + ((c2.h - h) * amount), s + ((c2.s - s) * amount), l + ((c2.l - l) * amount));
	}

	static void RgbToHsl(int color, HslColor hsl)
	{
		RgbToHsl(0xff & (color >> 0x10), 0xff & (color >> 8), 0xff & color, hsl);
	}

	static void RgbToHsl(int rr, int gg, int bb, HslColor& hsl)
	{
		double r = (rr / 255.0);
		double g = (gg / 255.0);
		double b = (bb / 255.0);

		double min = MIN(MIN(r, g), b);
		double max = MAX(MAX(r, g), b);
		double delta = max - min;

		// get luminance value
		hsl.l = (float)(max + min) / 2;

		if (delta == 0)
		{
			// gray color
			hsl.h = 0;
			hsl.s = 0.0f;
		}
		else
		{
			// get saturation value
			hsl.s = (float)((hsl.l < 0.5) ? (delta / (max + min)) : (delta / (2 - max - min)));

			// get hue value
			double del_r = (((max - r) / 6) + (delta / 2)) / delta;
			double del_g = (((max - g) / 6) + (delta / 2)) / delta;
			double del_b = (((max - b) / 6) + (delta / 2)) / delta;
			double hue;

			if (r == max)
				hue = del_b - del_g;
			else if (g == max)
				hue = (1.0 / 3) + del_r - del_b;
			else
				hue = (2.0 / 3) + del_g - del_r;

			// correct hue if needed
			if (hue < 0)
				hue += 1;
			if (hue > 1)
				hue -= 1;

			hsl.h = (int)(hue * 360);
		}
	}

};


/* 图片滤镜处理 */
class GDImageFilterUtil :
	public CAViewController
{
public:
	class YCbCr
	{
		/// <summary>
		/// Index of <b>Y</b> component.
		/// </summary>
	public:
		const static short YIndex = 0;

		/// <summary>
		/// Index of <b>Cb</b> component.
		/// </summary>
		const static short CbIndex = 1;

		/// <summary>
		/// Index of <b>Cr</b> component.
		/// </summary>
		const static short CrIndex = 2;

		/// <summary>
		/// <b>Y</b> component.
		/// </summary>
		float Y;

		/// <summary>
		/// <b>Cb</b> component.
		/// </summary>
		float Cb;

		/// <summary>
		/// <b>Cr</b> component.
		/// </summary>
		float Cr;

		/// <summary>
		/// Initializes a new instance of the <see cref="YCbCr"/> class.
		/// </summary>
		YCbCr() { };

		/// <summary>
		/// Initializes a new instance of the <see cref="YCbCr"/> class.
		/// </summary>
		/// 
		/// <param name="y"><b>Y</b> component.</param>
		/// <param name="cb"><b>Cb</b> component.</param>
		/// <param name="cr"><b>Cr</b> component.</param>
		/// 
		YCbCr(float y, float cb, float cr)
		{
			Y = max(0.0f, min(1.0f, y));
			Cb = max(-0.5f, min(0.5f, cb));
			Cr = max(-0.5f, min(0.5f, cr));
		}

		/// <summary>
		/// Convert from RGB to YCbCr color space (Rec 601-1 specification). 
		/// </summary>
		/// 
		/// <param name="rgb">Source color in <b>RGB</b> color space.</param>
		/// <param name="ycbcr">Destination color in <b>YCbCr</b> color space.</param>
		/// 
		static YCbCr FromRGB(Color rgb, YCbCr ycbcr)
		{
			float r = (float)rgb.R / 255;
			float g = (float)rgb.G / 255;
			float b = (float)rgb.B / 255;

			ycbcr.Y = (float)(0.2989 * r + 0.5866 * g + 0.1145 * b);
			ycbcr.Cb = (float)(-0.1687 * r - 0.3313 * g + 0.5000 * b);
			ycbcr.Cr = (float)(0.5000 * r - 0.4184 * g - 0.0816 * b);
			return ycbcr;
		}

		/// <summary>
		/// Convert from RGB to YCbCr color space (Rec 601-1 specification).
		/// </summary>
		/// 
		/// <param name="rgb">Source color in <b>RGB</b> color space.</param>
		/// 
		/// <returns>Returns <see cref="YCbCr"/> instance, which represents converted color value.</returns>
		/// 
		static YCbCr FromRGB(Color rgb)
		{
			YCbCr ycbcr;
			FromRGB(rgb, ycbcr);
			return ycbcr;
		}

		/// <summary>
		/// Convert from YCbCr to RGB color space.
		/// </summary>
		/// 
		/// <param name="ycbcr">Source color in <b>YCbCr</b> color space.</param>
		/// <param name="rgb">Destination color in <b>RGB</b> color spacs.</param>
		/// 
		static Color ToRGB(YCbCr ycbcr, Color rgb)
		{
			// don't warry about zeros. compiler will remove them
			float r = max(0.0f, min(1.0f, (float)(ycbcr.Y + 0.0000 * ycbcr.Cb + 1.4022 * ycbcr.Cr)));
			float g = max(0.0f, min(1.0f, (float)(ycbcr.Y - 0.3456 * ycbcr.Cb - 0.7145 * ycbcr.Cr)));
			float b = max(0.0f, min(1.0f, (float)(ycbcr.Y + 1.7710 * ycbcr.Cb + 0.0000 * ycbcr.Cr)));

			rgb.R = SAFECOLOR(r * 255);
			rgb.G = SAFECOLOR(g * 255);
			rgb.B = SAFECOLOR(b * 255);
			return rgb;
		}

		/// <summary>
		/// Convert the color to <b>RGB</b> color space.
		/// </summary>
		/// 
		/// <returns>Returns <see cref="RGB"/> instance, which represents converted color value.</returns>
		/// 
		/*Color ToRGB()
		{
		Color rgb;
		ToRGB(this, rgb);
		return rgb;
		}*/
	};

	class Range
	{

	public:
		float Min, Max;
		/// <summary>
		/// Length of the range (deffirence between maximum and minimum values).
		/// </summary>
		float Length()
		{
			return Max - Min;
		}

		Range() :Min(0), Max(0){}

		/// <summary>
		/// Initializes a new instance of the <see cref="Range"/> structure.
		/// </summary>
		/// 
		/// <param name="min">Minimum value of the range.</param>
		/// <param name="max">Maximum value of the range.</param>
		/// 
		Range(float min, float max) : Min(min), Max(max)
		{}
	};

public:
	virtual ~GDImageFilterUtil(){};

	static CAImage* modefyImage(CAImage *image, int filterId, float bright = 0, float contrast = 0, float saturation = 0, int hue = 0, int cbr = 0, int cbg = 0, int cbb = 0);
public:
	/* hsl h色相[0,359] s饱和度 l色阶 滤镜 hueFactor [0,359] */
	static CAImage* HslModifyFilter(CAImage *image, float hueFactor, float s = 0, float l = 0);
	/* YCB 滤镜 cb(-0.5f, 0.5f) cr(-0.5f, 0.5f) */
	static CAImage* YCBCrLinearFilter(CAImage *image, float minCb, float maxCb, float minCr = -0.5f, float maxCr = 0.5f);
	/* 灰色图片 */
	static CAImage* SpodogramFilter(CAImage *image);

	/* 亮度对比度滤镜 亮度BrightnessFactor[-1, 1] 对比度ContrastFactor[-1, 1] */
	static CAImage* BrightContrastFilter(CAImage *image, float BrightnessFactor = 0.25f, float ContrastFactor = 0);
	/* 饱和度滤镜[0,1] */
	static CAImage* SaturationFilter(CAImage *image, float Saturation = 0.5f);
	/* 图片滤镜处理 揉和 亮度、对比度、饱和度色相 */
	static CAImage* BCSHFilter(CAImage *image, float bright = 0, float contrast = 0, float saturation = 0, int hue = 0, int cbr = 0, int cbg = 0, int cbb = 0);
private:
	static CAImage* ImageFilter1(CAImage *image, int filterId);
	static CAImage* ImageFilter2(CAImage *image, int filterId);
	static CAImage* ImageFilter3(CAImage *image, int filterId);

	


	static unsigned char getRComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, int rgbaType = 3);
	static unsigned char getGComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, int rgbaType = 3);
	static unsigned char getBComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, int rgbaType = 3);
	static unsigned char getAComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col);

	static void setRComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, unsigned char value, int rgbaType = 3);
	static void setGComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, unsigned char value, int rgbaType = 3);
	static void setBComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, unsigned char value, int rgbaType = 3);
	static void setAComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, unsigned char value);
	static void setPixelColor(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, int color, int rgbaType = 3);
	static void setRGBComponent(unsigned char* _image, unsigned int& pixelsWide, unsigned int& pixelsHigh, int row, int col, unsigned char r, unsigned char g, unsigned char b, int rgbaType = 3, unsigned char a = 255);

};
#endif /* defined(__HelloCpp__ViewController__) */